﻿#include "ui/menu_items.h"
#include "draw.h"
#include "context.h"

using namespace std;
using namespace anip;

void ui::MenuSeparatorItem::paint()
{
	Draw::line(
		_absPos + vec2{ 0, _size.y * 0.5f },
		_absPos + vec2{ _size.x, _size.y * 0.5f }, 2.0f, r::Menu_Separator_Color);
}

void ui::MenuSeparatorItem::flow(Flow& f)
{
	setPosition({ f.currentX, f.currentY });
	_size.y = f.lineHeight = 4.0f;
	_size.x = _parent->size().x;
	f.currentX = 0;
	f.currentY += f.lineHeight;
}

ui::MenuTextItem::MenuTextItem(Menu& m, const wstring& text, CheckState ch) :
	WithText(m), check(ch)
{
	setText(text);
}

void ui::MenuTextItem::processMouseEnter()
{
	if (!enabled || _subMenu != nullptr)
	{
		WithText::processMouseEnter();
		return;
	}

	Menu* ps = _getParentSubMenu();
	if (ps != nullptr)
	{
		ps->markDelete();
		_reportSubMenu(nullptr);
	}

	postSignal({ ui::Signal::Type::NeedsRedraw });
	if (getSubMenu)
	{
		_subMenu = getSubMenu(*this);
		if (_subMenu != nullptr)
		{
			_reportSubMenu(_subMenu);
			_subMenu->setPosition(
				_subMenu->parent()->toLocalPos(_absPos + vec2{ _size.x, 0 }));
			_subMenu->onDeleting = [&](Control& self)
			{
				_subMenu = nullptr;
				_reportSubMenu(nullptr);
				if (!_menu.hovered())
					_menu.markDelete();
			};
		}
	}
	
	WithText::processMouseEnter();
}

void ui::MenuTextItem::processMouseLeave()
{
	if (enabled)
		postSignal({ ui::Signal::Type::NeedsRedraw });
	WithText::processMouseLeave();
}

void ui::MenuTextItem::processMouseButton(MouseButton btn, ButtonAction action)
{
	if (enabled)
	{
		postSignal({ ui::Signal::Type::NeedsRedraw });
		if (action == ButtonAction::Up)
		{
			if (onClick) onClick(*this);
		}
	}
	WithText::processMouseButton(btn, action);
}

void ui::MenuTextItem::paint()
{
	if (_hover && enabled)
	{
		color col = hoverColor;
		if (_press) col = col.mulWithoutAlpha(pressFactor);
		if (_prev == nullptr && !_menu.isDropdown)
		{
			Draw::roundedRect(_absPos, _size, _menu.roundRadius, col);
			Draw::rect(
				_absPos + vec2{ 0, _menu.roundRadius },
				_size - vec2{ 0, _menu.roundRadius }, col);
		}
		else if (_next == nullptr)
		{
			Draw::roundedRect(_absPos, _size, _menu.roundRadius, col);
			Draw::rect(
				_absPos,
				_size - vec2{ 0, _menu.roundRadius }, col);
		}
		else
			Draw::rect(_absPos, _size, col);
	}

	float margin = r::Menu_xMargin;
	color linecol = r::Menu_LineColor;

	Texture2D* textTex = getTextTexture();
	if (textTex != nullptr)
	{
		vec2 s = textTex->size();
		vec2 p = _absPos + vec2{ margin, (_size.y - s.y) * 0.5f };
		Draw::text(p, s, *textTex, enabled ? textColor() : linecol);
	}

	if (check > CheckState::NoCheck)
	{
		float siz = r::Menu_Check_OuterSize;
		Draw::ellipseOutline(
			_absPos + vec2{ (margin - siz) * 0.5f, (_size.y - siz) * 0.5f },
			{ siz, siz }, r::Menu_Check_RimSize, linecol);
	}
	if (check == CheckState::Checked)
	{
		float siz = r::Menu_Check_InnerSize;
		Draw::ellipse(
			_absPos + vec2{ (margin - siz) * 0.5f, (_size.y - siz) * 0.5f },
			{ siz, siz }, linecol);
	}
	if (getSubMenu)
	{
		Draw::line(
			_absPos + vec2{ _size.x - 15, _size.y * 0.5f - 5 },
			_absPos + vec2{ _size.x - 10, _size.y * 0.5f }, 2.0f, linecol);
		Draw::line(
			_absPos + vec2{ _size.x - 15, _size.y * 0.5f + 5 },
			_absPos + vec2{ _size.x - 10, _size.y * 0.5f }, 2.0f, linecol);
	}
}

void ui::MenuTextItem::flow(Flow& f)
{
	setPosition({ f.currentX, f.currentY });
	auto textTex = getTextTexture();
	if (textTex != nullptr)
	{
		vec2 ts = textTex->size();
		f.lineHeight = ts.y + r::Menu_yMargin * 2;
		_size.y = f.lineHeight;
		_size.x = max(_parent->size().x, ts.x + r::Menu_xMargin * 2);
	}
	f.currentX = 0;
	f.currentY += f.lineHeight;
}

ui::MenuLabelItem::MenuLabelItem(Menu& m, const wstring& text) :
	WithText(m)
{
	setText(text);
}

void ui::MenuLabelItem::paint()
{
	Texture2D* textTex = getTextTexture();
	if (textTex != nullptr)
	{
		vec2 s = textTex->size();
		vec2 p = _absPos + vec2{ r::Menu_xMargin, (_size.y - s.y) * 0.5f };
		Draw::text(p, s, *textTex, textColor);
	}
}

void ui::MenuLabelItem::flow(Flow& f)
{
	setPosition({ f.currentX, f.currentY });
	Texture2D* textTex = getTextTexture();
	if (textTex != nullptr)
	{
		vec2 ts = textTex->size();
		f.lineHeight = ts.y + r::Menu_yMargin * 2;
		_size.y = f.lineHeight;
		_size.x = max(_parent->size().x, ts.x + r::Menu_xMargin * 2);
	}
	f.currentX = 0;
	f.currentY += f.lineHeight;
}

void ui::MenuRadioBarSubItem::setText(const wstring& text)
{
	if (_tex != nullptr)
	{
		_tex->finalize();
		delete _tex;
		_tex = nullptr;
	}
	_text = text;
}

Texture2D* ui::MenuRadioBarSubItem::getTex()
{
	if (_tex == nullptr)
	{
		auto layout = TextRenderer::layoutPixelPerfectString(
			_text, ((MenuRadioBarItem&)_container).getFont());
		_tex = TextRenderer::renderString(*layout);
		delete layout;
	}
	return _tex;
}

ui::MenuRadioBarSubItem::~MenuRadioBarSubItem()
{
	if (_tex != nullptr)
	{
		_tex->finalize();
		delete _tex;
	}
}

void ui::MenuRadioBarItem::processMouseMove(invec2 pos)
{
	int index = (int)(pos.x / _size.x * items.size());
	if (index != _hoveredIndex && (unsigned int)index < items.size())
	{
		if (_hoveredIndex != -1)
		{
			items[_hoveredIndex]._hovered = false;
			items[_hoveredIndex]._pressed = false;
		}
		items[index]._hovered = true;
		_hoveredIndex = index;
		postSignal({ ui::Signal::Type::NeedsRedraw });
	}

	Control::processMouseMove(pos);
}

void ui::MenuRadioBarItem::processMouseLeave()
{
	if (_hoveredIndex != -1)
	{
		items[_hoveredIndex]._hovered = false;
		items[_hoveredIndex]._pressed = false;
		postSignal({ ui::Signal::Type::NeedsRedraw });
	}
	_hoveredIndex = -1;

	Control::processMouseLeave();
}

void ui::MenuRadioBarItem::processMouseButton(MouseButton btn, ButtonAction action)
{
	// ANIP_TODO more buttons?
	if (btn == MouseButton::Left && _hoveredIndex != -1)
	{
		auto& it = items[_hoveredIndex];
		postSignal({ ui::Signal::Type::NeedsRedraw });
		if (action == ButtonAction::Down)
		{
			it._pressed = true;
			it.toggle();
			if (it.onClick) it.onClick(it);
		}
		else if (action == ButtonAction::Up)
		{
			it._pressed = false;
		}
	}

	Control::processMouseButton(btn, action);
}

ui::MenuRadioBarSubItem& ui::MenuRadioBarItem::addItem(const wstring& text)
{
	items.push_back(MenuRadioBarSubItem(*this));
	auto& it = items[items.size() - 1];
	it.setText(text);
	return it;
}

void ui::MenuRadioBarItem::paint()
{
	// fixme: it should anyway draw when size() == 1
	if (items.size() < 2) return;

	if (_next == nullptr)
	{
		Draw::roundedRect(_absPos, _size, _menu.roundRadius, backColor);
		Draw::rect(_absPos,
			_size - vec2{ 0, _menu.roundRadius }, backColor);
	}
	else Draw::rect(_absPos, _size, backColor);

	int ind = 0;
	float cwid = _size.x / items.size();
	
	for (auto& i : items)
	{
		if (i._selected || i._hovered)
		{
			color col = i._selected ? selectedColor : hoverColor;
			if (i._selected && i._hovered)
				col = selectedColor().mulWithoutAlpha(hoverFactor);
			else if (i._hovered)
				col = hoverColor;
			if (i._pressed)
				col = col.mulWithoutAlpha(pressFactor);

			if (_next == nullptr)
			{
				if (ind == 0)
				{
					Draw::roundedRect(
						_absPos + vec2{ cwid * ind, 0 },
						{ cwid, _size.y }, _menu.roundRadius, col);
					Draw::rect(_absPos + vec2{ cwid * ind, 0 },
						{ cwid, _size.y - _menu.roundRadius }, col);
					Draw::rect(_absPos + vec2{ cwid * ind + _menu.roundRadius, 0 },
						{ cwid - _menu.roundRadius, _size.y }, col);
				}
				else if (ind == items.size() - 1)
				{
					Draw::roundedRect(
						_absPos + vec2{ cwid * ind, 0 },
						{ cwid, _size.y }, _menu.roundRadius, col);
					Draw::rect(_absPos + vec2{ cwid * ind, 0 },
						{ cwid, _size.y - _menu.roundRadius }, col);
					Draw::rect(_absPos + vec2{ cwid * ind, 0 },
						{ cwid - _menu.roundRadius, _size.y }, col);
				} else Context::clear(col);
			} else Context::clear(col);
		}

		Texture2D* tex = i.getTex();
		if (tex == nullptr) continue;
		vec2 s = tex->size();
		Draw::text(
			_absPos + vec2{ cwid * ind, 0 } + vec2{ cwid, _size.y } * 0.5f - s * 0.5f,
			s, *tex, textColor);

		ind++;
	}
}

void ui::MenuRadioBarItem::flow(Flow& f)
{
	setPosition({ f.currentX, f.currentY });

	float textSize = 0;
	for (auto& i : items)
	{
		Texture2D* tex = i.getTex();
		if (tex == nullptr) continue;
		textSize = max(tex->size().y, textSize);
	}

	f.lineHeight = textSize;
	_size.x = _parent->size().x;
	_size.y = textSize + r::Menu_yMargin * 2;

	f.currentX = 0;
	f.currentY += f.lineHeight;
}